﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using M3G;

/*
 * AnimationTrackとBind系の関数のテストはまだ未実装
 *   がんばれ > 俺
 * refreshもテストしてない
 */
/* 
 * SetUniformValue()の派生バージョンが全然テストしてない
 * そのうち作る
 * */
/*
 * uniformCount()とuniformAnimationCount()は仕様にないが追加した。わりとないと困る。
/*
 * よく見るとremoveUniform()が無いような?
 *   --> 削除できるとUniformIDが変化してしまうから
 *   　（なら素直にユニークにしろよと思わなくもない）
 * UniformAnimationの方は削除できるのでIDがない（それも不便なような...)
 * */
/* 
 * ここでテストしているのは基本的なShaderUniformsの機能だけ。
 * 詳細なテストは別ファイル
 * */

namespace MyTestProject {

    public class TestShaderUniforms {
        [Fact]
        public void TestConstructor () {
            var unifs = new ShaderUniforms ();

            Assert.Equal (0, unifs.UniformCount);
            Assert.Equal (0, unifs.AnimationTrackCount);
        }

        /*
         * Uniform変数の登録のテスト
         * */
        [Fact]
        public void TestAddUniform () {
            var unifs = new ShaderUniforms ();
            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.IVec4, 0);
            var trude = unifs.AddUniform ("Gertrud Barkhorn", ShaderVariableType.IVec4, 16);
            var mioVar = unifs.GetUniform (mio);
            var trudeVar = unifs.GetUniform (trude);

            Assert.Equal (2, unifs.UniformCount);

            Assert.Equal ("Sakamoto Mio", mioVar.Name);
            Assert.Equal (ShaderVariableType.IVec4, mioVar.Type);
            Assert.Equal (0, mioVar.ArraySize);

            Assert.Equal ("Gertrud Barkhorn", trudeVar.Name);
            Assert.Equal (ShaderVariableType.IVec4, trudeVar.Type);
            Assert.Equal (16, trudeVar.ArraySize);

            Assert.Equal (mio, unifs.GetUniformID("Sakamoto Mio"));
            Assert.Equal (trude, unifs.GetUniformID("Gertrud Barkhorn"));
        }


        /*
         * Uniform変数の値をセットするテスト
         * 代表してIVec4型のみ。詳細なテストは別ファイル
         * */
        [Fact]
        public void TestSetUniformValue () {
            var unifs = new ShaderUniforms ();
            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.IVec4, 0);

            // Unfimorm変数のの直接代入
            unifs.SetUniformValue (mio, 1924, 8, 26, 20);

            var mioValue = (int[])unifs.GetUniformValue(mio);
            Assert.Equal (4, mioValue.Length);
            Assert.Equal (1924, mioValue[0]);
            Assert.Equal (8, mioValue[1]);
            Assert.Equal (26, mioValue[2]);
            Assert.Equal (20, mioValue[3]);
        }

        /**
         * Uniform変数にObject3Dをバインドするテスト
         * 値の更新(refresh)などの詳細なテストは別ファイル
         * */
        [Fact]
        public void TestBindUniform () {
            var unifs = new ShaderUniforms ();
            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.Vec3, 0);
            var lgh   = new Light ();
            lgh.Color = 0x00123456;

            // Uniform変数mioに指定のオブジェクトをバインド
            unifs.SetObjectBinding (mio, lgh, "LightColor");
        
            // バインド設定の確認
            Object3D[] sources;
            
            Assert.Equal ("LightColor", unifs.GetObjectBinding (mio, out sources));
            Assert.Equal (lgh, sources[0]);
        }

        /**
         * Uniform変数にTransform(Object3D-Object3D)をバインドするテスト
         * 値の更新(refresh)などの詳細なテストは別ファイル
         * */
        [Fact]
        public void TestBindTransofrm () {
            var unifs = new ShaderUniforms ();
            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.Vec3, 0);
            var fromNode  = new Group ();
            var toNode    = new Group ();

            // Uniform変数mioに指定のTransform(Object,Object)をバインド
            unifs.SetTransformBinding (mio, fromNode, toNode);

            // バインド設定の確認
            Node[] from;
            Node[] to;
            Assert.Equal (1, unifs.GetTransformBinding (mio, out from, out to));
            Assert.Equal (fromNode, from[0]);
            Assert.Equal (toNode, to[0]);

        }

        /*
         * Uniform変数にアニメーションをセットするテスト
         * 値の更新(animate,refresh)のテストは別ファイル
         * */
        [Fact]
        public void TestAddAnimationTrack () {
            var unifs = new ShaderUniforms ();
            var kseq = new KeyframeSequence (4, 3, KeyframeSequence.Step);
            var anim = new AnimationTrack (kseq, ShaderVariableType.Vec3, false);

            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.Vec3, 0);

            unifs.AddAnimationTrack (mio, anim);

            Assert.Equal (1, unifs.AnimationTrackCount);
            Assert.Equal (mio, unifs.AnimationTrackUniform[0]);
            Assert.Equal (anim, unifs.AnimationTrack[0]);
            Assert.Equal (0, unifs.AnimationTrackChannel[0]);
        }

        /*
　　　　 * Uniform変数にセットしたアニメーションを削除するテスト
 　　　　* （これ全然難しそうに見えないけど内部的にすごく間違えやすい処理を行っている）
 　　　　* */
        [Fact]
        public void TestRemoveAnimationTrack () {
            var unifs = new ShaderUniforms ();
            var kseq = new KeyframeSequence (2, 4, 3, KeyframeSequence.Step); // 2 channels
            var anim1 = new AnimationTrack (kseq, ShaderVariableType.Vec3, false);
            var anim2 = new AnimationTrack (kseq, ShaderVariableType.Vec3, false);

            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.Vec3, 0);
            var peri  = unifs.AddUniform ("Perrine H. Clostermann", ShaderVariableType.Vec3, 0);
            var lyne  = unifs.AddUniform ("Lynette Bishop", ShaderVariableType.Vec3, 0);

            unifs.AddAnimationTrack (mio, anim1, 0);  // channel 0
            unifs.AddAnimationTrack (peri, anim2, 1); // channel 1
            unifs.AddAnimationTrack (lyne, anim1);    // channel 0

            // アニメーションは３つ
            Assert.Equal (3, unifs.AnimationTrackCount);
            Assert.Equal (mio, unifs.AnimationTrackUniform[0]);
            Assert.Equal (peri, unifs.AnimationTrackUniform[1]);
            Assert.Equal (lyne, unifs.AnimationTrackUniform[2]);

            // mioとlyneに設定されたアニメーションを両方削除
            unifs.RemoveAnimationTrack (anim1);

            // index=0でPerrineに設定されたアニメーションがで取得できるように繰り上がる
            Assert.Equal (1, unifs.AnimationTrackCount);
            Assert.Equal (peri, unifs.AnimationTrackUniform[0]);
            Assert.Equal (anim2, unifs.AnimationTrack[0]);
            Assert.Equal (1, unifs.AnimationTrackChannel[0]);
        }

        [Fact]
        public void TestDuplicate () {
            var unifs = new ShaderUniforms ();
            var kseq = new KeyframeSequence (4, 3, KeyframeSequence.Step);
            var anim = new AnimationTrack (kseq, ShaderVariableType.Vec3, false);

            var mio   = unifs.AddUniform ("Sakamoto Mio", ShaderVariableType.Vec3, 0);
            unifs.AddAnimationTrack (mio, anim);
            unifs.UserID = 100;

            var dup = (ShaderUniforms)unifs.Duplicate ();

            Assert.Equal (unifs.UniformCount, dup.UniformCount);

            Assert.Equal (unifs.GetUniform(mio).Name, dup.GetUniform(mio).Name);
            Assert.Equal (unifs.GetUniform(mio).Type, dup.GetUniform(mio).Type);
            Assert.Equal (unifs.GetUniform(mio).ArraySize, dup.GetUniform(mio).ArraySize);
            Assert.Equal (unifs.UserID, dup.UserID);
        }


    }

}
